Periodic multiple channel ADC read

  • User specified:
    • Sample frequency, $f_s$
    • List of ADC channels $C = \left[c_0, c_1, \ldots c_n\right]$.
  • After each $\frac{1}{f_s}$ period, measure value for each channel in $C$ as quickly as possible.

Plan

Measure all channels once

|ADC READ |   ADC WAIT  |ADC READ |   ADC WAIT   |
|[0]                    |[0]                     | ->  [r0]
|   [1]                 |   [1]                  | ->  [r1]
|      [2]              |      [2]               | ->  [r2]

|<-------- 1/f_s ------>|


Configure 3 DMA channels (one "ADC READ" in the above diagram):

  1. Copy channel configuration to ADC config register (SW triggered, and linked to channel 3).
  2. Copy ADC start to ADC register (linked to channel 1).
  3. Copy ADC result to output array (triggered by ADC conversion complete, i.e., COCO)

Period ($\frac{1}{f_s}$)

Trigger ADC READ periodically.

Method 1: Timer interrupt

  • Set Periodic Interrupt Timer to period of $\frac{1}{f_s}$
  • In timer interrupt service routine:
    1. Software trigger DMA channel 1, causing linked read of all channels.

Advantages:

  • Flexibility, since ISR code can do other things, e.g., increment counters, etc.

Disadvantages:

  • Ties up CPU.

Method 2: Timer DMA trigger

  • Set Periodic Interrupt Timer to period of $\frac{1}{f_s}$
  • Configure DMA channel 1 to use PIT trigger, causing linked read of all channels with no CPU intervention.

Advantages:

  • Runs without CPU intervention, i.e., in background.
  • Should have higher max sampling rate (assuming ADC is not bottleneck)

Disadvantages:

  • Harder to do things like incrementing counters, etc.

Continuous RMS, peak-to-peak, etc.?

  • Compute RMS across most recent $n$ periods.

In [4]:
from IPython.display import display
from datetime import datetime

import numpy as np
import pandas as pd
import arduino_helpers.hardware.teensy as teensy
from arduino_helpers.hardware.teensy.adc import ADC_DESCRIPTIONS
from arduino_helpers.hardware.teensy.dma import (TCD_DESCRIPTIONS,
                                                 REGISTERS_DESCRIPTIONS
                                                 as DMA_REG_DESCRIPTIONS,
                                                 DCHPRI_DESCRIPTIONS)
from arduino_helpers.hardware.teensy.pit import (TIMER_CONFIG_DESCRIPTIONS,
                                                 REGISTERS_DESCRIPTIONS
                                                 as PIT_REG_DESCRIPTIONS)
import arduino_helpers.hardware.arduino as arduino
from arduino_rpc.protobuf import resolve_field_values

from teensy_minimal_rpc import SerialProxy
import teensy_minimal_rpc.ADC as adc
import teensy_minimal_rpc.DMA as dma
import teensy_minimal_rpc.SIM as sim
import teensy_minimal_rpc.PIT as pit


def init_dma(proxy):
    # SIM_SCGC7 |= SIM_SCGC7_DMA;
    # SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
    proxy.update_sim_SCGC6(sim.R_SCGC6(DMAMUX=True))
    proxy.update_sim_SCGC7(sim.R_SCGC7(DMA=True))
    for i in xrange(proxy.dma_channel_count()):
        # TCD = (TCD_t *)(0x40009000 + ch * 32);
        # uint32_t *p = (uint32_t *)TCD;
        # *p++ = 0;
        # *p++ = 0;
        # *p++ = 0;
        # *p++ = 0;
        # *p++ = 0;
        # *p++ = 0;
        # *p++ = 0;
        # *p++ = 0;
        proxy.reset_dma_TCD(i)

In [67]:
try:
    del proxy
except NameError:
    pass

proxy = SerialProxy(baudrate=512000)

proxy.pin_mode(13, 1)
proxy.digital_write(13, 1)
init_dma(proxy)
# proxy.enableDMA(teensy.ADC_0)
# proxy.enableInterrupts(teensy.ADC_0)
# proxy.dma_start(256)

# Set ADC parameters
# proxy.setAveraging(4, teensy.ADC_0)
# proxy.setResolution(10, teensy.ADC_0)
# proxy.setConversionSpeed(teensy.ADC_VERY_HIGH_SPEED, teensy.ADC_0)
# proxy.setSamplingSpeed(teensy.ADC_VERY_HIGH_SPEED, teensy.ADC_0)

Allocate two arrays: source and destination


In [68]:
N = 512
proxy.free_all()
src_addr = proxy.mem_alloc(N)
dst_addr = proxy.mem_alloc(N)
proxy.mem_cpy_host_to_device(src_addr, np.arange(1, 17, dtype='uint8'))
proxy.mem_fill_uint32(dst_addr, 0, N / 4)
[hex(addr)[:-1] for addr in (src_addr, dst_addr)]


Out[68]:
['0x1fffe6d8', '0x1fffe8f0']

In [77]:
XFER_REQUEST = dma.TCD(CSR=dma.R_TCD_CSR(START=1),
                       NBYTES_MLNO=8,
                       SADDR=int(src_addr + 15),
                       DADDR=int(dst_addr),
                       SOFF=-1,
                       DOFF=4,
                       ATTR=dma.R_TCD_ATTR(SSIZE=dma.R_TCD_ATTR._8_BIT,
                                           DSIZE=dma.R_TCD_ATTR._32_BIT),
                       SLAST=16,
                       DLASTSGA=-16,
                       CITER_ELINKNO=dma.R_TCD_ITER_ELINKNO(ITER=2),
                       BITER_ELINKNO=dma.R_TCD_ITER_ELINKNO(ITER=2),
                       )

In [78]:
proxy.mem_fill_uint32(dst_addr, 0, N / 4)
request = dma.TCD()
request.CopyFrom(XFER_REQUEST)
request.CSR.START = 0
proxy.update_dma_TCD(1, request)


Out[78]:
0

In [94]:
proxy.mem_fill_uint32(dst_addr, 0, N / 4)
proxy.update_dma_registers(dma.Registers(SSRT=1))
proxy.mem_cpy_device_to_host(dst_addr, 20)


Out[94]:
array([0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0], dtype=uint8)

In [18]:
proxy.update_dma_TCD(0, XFER_REQUEST)
tcd0 = dma.TCD.FromString(proxy.read_dma_TCD(0).tostring())
df_tcd0 = resolve_field_values(tcd0)
display(df_tcd0[['full_name', 'value']].dropna()
        .join(TCD_DESCRIPTIONS, on='full_name')
        [['full_name', 'value', 'short_description', 'page']]
        .sort_values(['page','full_name']))


full_name value short_description page
parent_name
SADDR 536864472 Source Address 21.3.17/415
SOFF 4 Source Address Signed offset 21.3.18/415
ATTR ATTR.DMOD 0 Destination Address Modulo 21.3.19/416
ATTR ATTR.DSIZE _32_BIT Destination data transfer size 21.3.19/416
ATTR ATTR.SMOD 0 Source Address Modulo. 21.3.19/416
ATTR ATTR.SSIZE _32_BIT Source data transfer size 21.3.19/416
NBYTES_MLNO 16 Minor Byte Transfer Count 21.3.20/417
SLAST -16 Last source Address Adjustment 21.3.23/420
DADDR 536865008 Destination Address 21.3.24/420
DOFF 4 Destination Address Signed offset 21.3.25/421
CITER_ELINKNO CITER_ELINKNO.ELINK False Enable channel-to-channel linking on minor-loo... 21.3.27/422
CITER_ELINKNO CITER_ELINKNO.ITER 1 Current Major Iteration Count 21.3.27/422
DLASTSGA -16 Destination last address adjustment or the mem... 21.3.28/423
CSR CSR.ACTIVE False Channel Active 21.3.29/424
CSR CSR.BWC NO_STALLS Bandwidth Control 21.3.29/424
CSR CSR.DONE True Channel Done 21.3.29/424
CSR CSR.DREQ False Disable Request 21.3.29/424
CSR CSR.ESG False Enable Scatter/Gather Processing 21.3.29/424
CSR CSR.INTHALF False Enable an interrupt when major counter is half... 21.3.29/424
CSR CSR.INTMAJOR False Enable an interrupt when major iteration count... 21.3.29/424
CSR CSR.MAJORELINK False Enable channel-to-channel linking on major loo... 21.3.29/424
CSR CSR.MAJORLINKCH 0 Link Channel Number 21.3.29/424
CSR CSR.START False Channel Start 21.3.29/424
BITER_ELINKNO BITER_ELINKNO.ELINK False Enable channel-to-channel linking on minor-loo... 21.3.31/427
BITER_ELINKNO BITER_ELINKNO.ITER 1 Beginning Major Iteration Count 21.3.31/427

In [ ]:


In [89]:
dchpri0 = dma.DCHPRI.FromString(proxy.read_dma_priority(0).tostring())
df_dchpri0 = resolve_field_values(dchpri0)
display(df_dchpri0[['full_name', 'value']].dropna().join(DCHPRI_DESCRIPTIONS, on='full_name'))


full_name value short_description description page
parent_name
CHPRI 0 Channel n Arbitration Priority Channel priority when fixed-priority arbitrati... 21.3.16/414
DPA False Disable Preempt Ability 0: Channel n can suspend a lower priority chan... 21.3.16/414
ECP False Enable Channel Preemption 0: Channel n cannot be suspended by a higher p... 21.3.16/414

In [94]:
proxy.update_dma_registers(CERQ=0)  # (ES=dma.R_ES())


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-94-555d249af41d> in <module>()
----> 1 proxy.update_dma_registers(CERQ=0)  # (ES=dma.R_ES())

TypeError: update_dma_registers() got an unexpected keyword argument 'CERQ'

In [93]:
dma_registers = dma.Registers.FromString(proxy.read_dma_registers().tostring())
df_dma = resolve_field_values(dma_registers)
display(df_dma.dropna(subset=['value'])
        .join(DMA_REG_DESCRIPTIONS, on='full_name')
        [['full_name', 'value', 'short_description', 'page']])


full_name value short_description page
parent_name
ERQ 0 Enable Request Register 21.3.3/394
ERR 1 Error Register 21.3.14/409
INT 0 Interrupt Request Register 21.3.13/406
EEI 0 Enable Error Interrupt Register 21.3.4/397
HRS 0 Hardware Request Status Register 21.3.15/411
ES ES.DAE False Destination Address Error 21.3.2/392
ES ES.SOE False Source Offset Error 21.3.2/392
ES ES.DBE False Destination Bus Error 21.3.2/392
ES ES.ERRCHN 0 Error Channel Number or Cancelled Channel Number 21.3.2/392
ES ES.CPE False Channel Priority Error 21.3.2/392
ES ES.SAE False Source Address Error 21.3.2/392
ES ES.VLD True Logical OR of all ERR status bits 21.3.2/392
ES ES.SBE False Source Bus Error 21.3.2/392
ES ES.DOE False Destination Offset Error 21.3.2/392
ES ES.SGE False Scatter/Gather Configuration Error 21.3.2/392
ES ES.NCE True NBYTES/CITER Configuration Error 21.3.2/392
ES ES.ECX False Transfer Cancelled 21.3.2/392
CR CR.CLM False Continuous Link Mode 21.3.1/391
CR CR.HOE False Halt On Error 21.3.1/391
CR CR.HALT False Halt DMA Operations 21.3.1/391
CR CR.EDBG False Enable Debug 21.3.1/391
CR CR.CX False Cancel Transfer 21.3.1/391
CR CR.EMLM False Enable Minor Loop Mapping 21.3.1/391
CR CR.ERCA False Enable Round Robin Channel Arbitration 21.3.1/391
CR CR.ECX False Error Cancel Transfer 21.3.1/391

In [52]:
init_dma(proxy)
proxy.update_dma_TCD(0, dma.TCD(CSR=dma.R_TCD_CSR(BWC=dma.R_TCD_CSR.NO_STALLS)))
tcd0 = dma.TCD.FromString(proxy.read_dma_TCD(0).tostring())
df_tcd0 = resolve_field_values(tcd0)
display(df_tcd0[['full_name', 'value']].dropna()
        .join(TCD_DESCRIPTIONS, on='full_name')
        [['full_name', 'value', 'short_description', 'page']]
        .sort_values(['page','full_name']))


full_name value short_description page
parent_name
SADDR 0 Source Address 21.3.17/415
SOFF 0 Source Address Signed offset 21.3.18/415
ATTR ATTR.DMOD 0 Destination Address Modulo 21.3.19/416
ATTR ATTR.DSIZE _8_BIT Destination data transfer size 21.3.19/416
ATTR ATTR.SMOD 0 Source Address Modulo. 21.3.19/416
ATTR ATTR.SSIZE _8_BIT Source data transfer size 21.3.19/416
NBYTES_MLNO 0 Minor Byte Transfer Count 21.3.20/417
SLAST 0 Last source Address Adjustment 21.3.23/420
DADDR 0 Destination Address 21.3.24/420
DOFF 0 Destination Address Signed offset 21.3.25/421
CITER_ELINKNO CITER_ELINKNO.ELINK False Enable channel-to-channel linking on minor-loo... 21.3.27/422
CITER_ELINKNO CITER_ELINKNO.ITER 0 Current Major Iteration Count 21.3.27/422
DLASTSGA 0 Destination last address adjustment or the mem... 21.3.28/423
CSR CSR.ACTIVE False Channel Active 21.3.29/424
CSR CSR.BWC NO_STALLS Bandwidth Control 21.3.29/424
CSR CSR.DONE False Channel Done 21.3.29/424
CSR CSR.DREQ False Disable Request 21.3.29/424
CSR CSR.ESG False Enable Scatter/Gather Processing 21.3.29/424
CSR CSR.INTHALF False Enable an interrupt when major counter is half... 21.3.29/424
CSR CSR.INTMAJOR False Enable an interrupt when major iteration count... 21.3.29/424
CSR CSR.MAJORELINK False Enable channel-to-channel linking on major loo... 21.3.29/424
CSR CSR.MAJORLINKCH 0 Link Channel Number 21.3.29/424
BITER_ELINKNO BITER_ELINKNO.ELINK False Enable channel-to-channel linking on minor-loo... 21.3.31/427
BITER_ELINKNO BITER_ELINKNO.ITER 0 Beginning Major Iteration Count 21.3.31/427

In [30]:
adc0 = adc.Registers.FromString(proxy.read_adc_registers(0).tostring())
df_adc0 = resolve_field_values(adc0)
display(df_adc0[['full_name', 'value']].dropna())


full_name value
parent_name
CLMD 13
CLPS 44
CLMS 42
CLPD 15
PG 33468
RB 0
RA 0
OFS 1
MG 33469
CLP1 86
CLP0 43
CLP3 339
CLP2 172
CV2 0
CLP4 670
CV1 0
CLM2 160
CLM3 318
CLM0 41
CLM1 81
CLM4 632
CFG2 CFG2.MUXSEL B
CFG2 CFG2.ADLSTS ADD_12_ADCK_CYCLES
CFG2 CFG2.ADHSC False
CFG2 CFG2.ADACKEN False
CFG1 CFG1.ADICLK BUS_CLOCK_DIV_2
CFG1 CFG1.MODE _10_BIT
CFG1 CFG1.ADIV EIGHT
CFG1 CFG1.ADLPC True
SC1A SC1A.COCO True
SC1A SC1A.DIFF False
SC1A SC1A.AIEN False
SC1A SC1A.ADCH 31
SC1B SC1B.COCO False
SC1B SC1B.DIFF False
SC1B SC1B.AIEN False
SC1B SC1B.ADCH 31
PGA PGA.PGAEN False
PGA PGA.PGALPB False
PGA PGA.PGAG _1
SC3 SC3.AVGE True
SC3 SC3.ADCO False
SC3 SC3.AVGS _32
SC3 SC3.CALF False
SC3 SC3.CAL False
SC2 SC2.DMAEN False
SC2 SC2.REFSEL DEFAULT
SC2 SC2.ADACT False
SC2 SC2.ACFGT False
SC2 SC2.ADTRG SOFTWARE
SC2 SC2.ACREN False
SC2 SC2.ACFE False

In [31]:
proxy.update_sim_SCGC6(sim.R_SCGC6(PIT=True))


Out[31]:
0

In [51]:
scgc6 = sim.R_SCGC6.FromString(proxy.read_sim_SCGC6().tostring())
df_scgc6_fields = resolve_field_values(scgc6)
display(df_scgc6_fields[['full_name', 'value']].dropna().T)

scgc7 = sim.R_SCGC7.FromString(proxy.read_sim_SCGC7().tostring())
df_scgc7_fields = resolve_field_values(scgc7)
display(df_scgc7_fields[['full_name', 'value']].dropna().T)


parent_name
full_name USBDCD SPI0 SPI1 RTC FTM1 FTM0 I2S DMAMUX CRC FTFL ADC0 FLEXCAN0 PIT PDB
value False False False True True True False False False True True False False False
parent_name
full_name DMA
value True

In [33]:
pit_registers = pit.Registers.FromString(proxy.read_pit_registers().tostring())
df_pit_registers = resolve_field_values(pit_registers)
display(df_pit_registers[['full_name', 'value']].dropna())

pit_tmr0 = pit.TimerConfig.FromString(proxy.read_pit_timer_config(0).tostring())
df_pit_tmr0 = resolve_field_values(pit_tmr0)
display(df_pit_tmr0[['full_name', 'value']].dropna()
        .join(TIMER_CONFIG_DESCRIPTIONS, on='full_name'))


full_name value
parent_name
MCR MCR.FRZ False
MCR MCR.MDIS True
full_name value short_description description page
parent_name
LDVAL 0 Timer Start Value Sets the timer start value. The timer will cou... 37.3.2/904
CVAL 0 Current Timer Value Represents the current timer value, if the tim... 37.3.3/905
TCTRL TCTRL.TIE False Timer Interrupt Enable When an interrupt is pending, or, TFLGn[TIF] i... 37.3.4/905
TCTRL TCTRL.TEN False Timer Enable Enables or disables the timer. 0: Timer n is d... 37.3.4/905
TCTRL TCTRL.CHN False Chain Mode When activated, Timer n-1 needs to expire befo... 37.3.4/905
TFLG TFLG.TIF False Timer Interrupt Flag Sets to 1 at the end of the timer period. Writ... 37.3.5/906

In [34]:
proxy.D__F_CPU(), proxy.D__F_BUS()


Out[34]:
(96000000, 48000000)

In [35]:
proxy.dma_channel_count()


Out[35]:
16

In [36]:
frames = []

for i in xrange(proxy.dma_channel_count()):
    tcd = dma.TCD.FromString(proxy.read_dma_TCD(i).tostring())
    frame = resolve_field_values(tcd)
    frame.insert(0, 'channel', i)
    frames.append(frame)

df_tdc_fields = pd.concat(frames)
# df_tdc_fields[['channel', 'full_name', 'value']].dropna().loc['CSR']

In [49]:
# tcd.CSR.BWC = dma.R_TCD_CSR.E_BWC.Value('STALL_4_CYCLES')
tcd = dma.TCD(SADDR=1234)
# tcd.CSR.BWC = dma.R_TCD_CSR.E_BWC.Value('NO_STALLS')
proxy.update_dma_TCD(0, tcd.SerializeToString())


Out[49]:
0

In [13]:
tcd.SADDR = 1234
tcd.SLAST = -1
tcd.DADDR = 4321
tcd.DLASTSGA = -1
tcd.NBYTES_MLNO = 4
tcd.CSR.BWC = dma.R_TCD_CSR.E_BWC.Value('NO_STALLS')
proxy.update_dma_TCD(0, tcd.SerializeToString())


Out[13]:
0

In [45]:
# addr = proxy.mem_aligned_alloc_and_set(range(16), 16)
# addr = proxy.mem_aligned_alloc(16, 24)
# proxy.ram_free()
N = 512
src_addr = proxy.mem_alloc(N)
dst_addr = proxy.mem_alloc(N)
[hex(addr)[:-1] for addr in (src_addr, dst_addr)]


Out[45]:
['0x1fffe6a0', '0x1fffe8a8']

In [39]:
%timeit proxy.mem_cpy_device_to_host(src_addr, N)


10 loops, best of 3: 32.2 ms per loop

In [40]:
for addr in (src_addr, dst_addr):
    proxy.mem_fill_uint32(addr, 0, N / 4)

In [42]:
import numpy as np

N_i = N / 2 / 2

for i in xrange(2):
    proxy.mem_cpy_host_to_device(src_addr + i * N_i * 2, np.arange(i * N_i, (i + 1) * N_i, dtype='uint16').view('uint8'))

In [43]:
print proxy.mem_cpy_device_to_host(src_addr, N).view('uint16')
print proxy.mem_cpy_device_to_host(dst_addr, N).view('uint16')


[  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17
  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35
  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53
  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71
  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89
  90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107
 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
 252 253 254 255]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

In [44]:
for addr in (src_addr, dst_addr):
    proxy.mem_free(addr)

In [16]:
proxy.mem_fill_uint16(src_addr + 4, 65000, 4)

In [46]:
proxy.mem_cpy_device_to_host(addr, 8)


Out[46]:
array([0, 0, 0, 0, 0, 0, 0, 0], dtype=uint8)

In [4]:
proxy.mem_cpy_device_to_host(0x40009000, 4 * 32)


Out[4]:
array([ 16, 176,   3,  64,   0,   0,  73,   1,   2,   0,   0,   0,   0,
         0,   0,   0,   0, 144, 255,  31,   2,   0,   1,   0,   0,   0,
         0,   0,   2,   0,   1,   0,  83, 199,  90, 166, 189,  85,   2,
       240, 215,  39, 185, 176,  29, 237, 209, 100, 246, 252,   6, 124,
        55,  39, 182, 205, 189,  41,  86, 246,  52,  39, 124, 100, 146,
         7, 105, 173, 192, 114, 217,  77, 232,  46,  62,  80, 176,  79,
       250,  94,  46, 110, 222, 235,  29, 224, 200, 148,  95, 234, 122,
       216,   6, 205, 253, 153, 178, 219,  16, 148,  92, 173,  33, 228,
       118, 179,   3, 111, 195, 237, 240,  29, 153,   2, 206, 148, 125,
       163, 203,  98, 242, 134, 219,  58,  62, 163, 104,   1], dtype=uint8)

In [21]:
addrs = [proxy.do_aligned_alloc(4, 128) for i in xrange(8)]
addrs


Out[21]:
[536864172,
 536864316,
 536864460,
 536864604,
 536864748,
 536864892,
 536865036,
 536865180]

In [14]:
addrs = [proxy.do_aligned_alloc(4, 128) for i in xrange(8)]
addrs


Out[14]:
[536864172,
 536864316,
 536864460,
 536864604,
 536864748,
 536864892,
 536865036,
 536865180]

In [22]:
for addr in addrs:
    proxy.do_aligned_free(addr)

In [6]:
tcd = dma.TCD.FromString(proxy.read_dma_TCD(0).tostring())

df_tdc_fields = resolve_field_values(tcd)
df_tdc_fields[['full_name', 'value']].dropna()


Out[6]:
full_name value
parent_name
DLASTSGA 0
SLAST 0
SOFF 0
DOFF 2
DADDR 536842240
SADDR 1073983504
CITER_ELINKNO CITER_ELINKNO.ELINK False
CITER_ELINKNO CITER_ELINKNO.ITER 1
ATTR ATTR.SMOD 0
ATTR ATTR.DSIZE _16_BIT
ATTR ATTR.DMOD 9
ATTR ATTR.SSIZE _16_BIT
BITER_ELINKNO BITER_ELINKNO.ELINK False
BITER_ELINKNO BITER_ELINKNO.ITER 1
NBYTES_MLOFFNO NBYTES_MLOFFNO.SMLOE False
NBYTES_MLOFFNO NBYTES_MLOFFNO.DMLOE False
NBYTES_MLOFFNO NBYTES_MLOFFNO.NBYTES 2
CSR CSR.INTHALF False
CSR CSR.DREQ False
CSR CSR.MAJORELINK False
CSR CSR.MAJORLINKCH 0
CSR CSR.ESG False
CSR CSR.START False
CSR CSR.BWC NO_STALLS
CSR CSR.DONE False
CSR CSR.ACTIVE False
CSR CSR.INTMAJOR True

In [14]:
scgc6 = sim.R_SCGC6.FromString(proxy.read_sim_SCGC6().tostring())

df_scgc6_fields = resolve_field_values(scgc6)
df_scgc6_fields[['full_name', 'value']].dropna().T


Out[14]:
parent_name
full_name USBDCD SPI0 SPI1 RTC FTM1 FTM0 I2S DMAMUX CRC FTFL ADC0 FLEXCAN0 PIT PDB
value False False False False True True False True False True True False False False

In [29]:
scgc7 = sim.R_SCGC7.FromString(proxy.read_sim_SCGC7().tostring())

df_scgc7_fields = resolve_field_values(scgc7)
df_scgc7_fields[['full_name', 'value']].dropna().T


Out[29]:
parent_name
full_name DMA
value True

In [43]:
proxy.startSingleRead(teensy.A1, teensy.ADC_0)


Out[43]:
1

In [58]:
proxy.adc_read()


Out[58]:
array([0, 0], dtype=uint16)

In [65]:
adc0_registers = adc.Registers.FromString(proxy.read_adc_registers(0).tostring())
df_fields = resolve_field_values(adc0_registers).join(ADC_DESCRIPTIONS, on='full_name') 
df_fields.loc[(df_fields.index != '') |
              df_fields.full_name.str.startswith('R'),
              ['full_name', 'value', 'short_description']]


Out[65]:
full_name value short_description
parent_name
RB 0 ADC Data Result Register
RA 0 ADC Data Result Register
CFG2 CFG2.MUXSEL A ADC mux select
CFG2 CFG2.ADLSTS ADD_6_ADCK_CYCLES Long sample time select
CFG2 CFG2.ADHSC True High-speed configuration
CFG2 CFG2.ADACKEN False Asynchronous clock output enable
CFG1 CFG1.ADLSMP SHORT Sample time configuration
CFG1 CFG1.ADICLK BUS_CLOCK_DIV_2 Input clock select
CFG1 CFG1.MODE _10_BIT Conversion mode selection
CFG1 CFG1.ADIV ONE Clock divide select
CFG1 CFG1.ADLPC False Low-power configuration
SC1A SC1A.COCO False Conversion complete flag
SC1A SC1A.DIFF False Differential mode enable
SC1A SC1A.AIEN True Interrupt enable
SC1A SC1A.ADCH 31 Input channel select
SC1B SC1B.COCO False Conversion complete flag
SC1B SC1B.DIFF False Differential mode enable
SC1B SC1B.AIEN False Interrupt enable
SC1B SC1B.ADCH 31 Input channel select
PGA PGA.PGAEN False PGA enable
PGA PGA.PGALPb False PGA low-power mode control
PGA PGA.PGAG _1 PGA Gain setting, $PGA~gain = 2^{PGAG}$
SC3 SC3.AVGE True Hardware average enable
SC3 SC3.ADCO False Continuous conversion enable
SC3 SC3.AVGS _4 Hardware average select
SC3 SC3.CALF False Calibration failed flag
SC3 SC3.CAL False Calibration
SC2 SC2.DMAEN True DMA enable
SC2 SC2.REFSEL DEFAULT Voltage reference selection
SC2 SC2.ADACT False Conversion active
SC2 SC2.ACFGT False Compare function greater than enable
SC2 SC2.ADTRG SOFTWARE Conversion trigger select
SC2 SC2.ACREN False Compare function range enable
SC2 SC2.ACFE False Compare function enable

In [24]:
teensy.adc.SC1A_TO_CHANNEL_ADC0[df_fields.set_index('full_name').loc['SC1A.ADCH'].value]
teensy.adc.CHANNEL_TO_SC1A_ADC0[teensy.A0]


Out[24]:
5

In [16]:
proxy.analogRead(teensy.A0, teensy.ADC_0)


Out[16]:
1023

In [36]:
[(k.full_name, v) for k, v in adc0_registers.ListFields()]


Out[36]:
[('teensy._3_1.ADC_REGISTERS.SC1A', <ADC_pb2.R_SC1 at 0xa2b6630>),
 ('teensy._3_1.ADC_REGISTERS.SC1B', <ADC_pb2.R_SC1 at 0xa2b6770>),
 ('teensy._3_1.ADC_REGISTERS.CFG1', <ADC_pb2.R_CFG1 at 0xa2b6670>),
 ('teensy._3_1.ADC_REGISTERS.CFG2', <ADC_pb2.R_CFG2 at 0xa2b66b0>),
 ('teensy._3_1.ADC_REGISTERS.RA', 0),
 ('teensy._3_1.ADC_REGISTERS.RB', 0),
 ('teensy._3_1.ADC_REGISTERS.CV1', 0),
 ('teensy._3_1.ADC_REGISTERS.CV2', 0),
 ('teensy._3_1.ADC_REGISTERS.SC2', <ADC_pb2.R_SC2 at 0xa2b67b0>),
 ('teensy._3_1.ADC_REGISTERS.SC3', <ADC_pb2.R_SC3 at 0xa2b67f0>),
 ('teensy._3_1.ADC_REGISTERS.OFS', 65535),
 ('teensy._3_1.ADC_REGISTERS.PG', 33479),
 ('teensy._3_1.ADC_REGISTERS.MG', 33444),
 ('teensy._3_1.ADC_REGISTERS.CLPD', 18),
 ('teensy._3_1.ADC_REGISTERS.CLPS', 46),
 ('teensy._3_1.ADC_REGISTERS.CLP4', 705),
 ('teensy._3_1.ADC_REGISTERS.CLP3', 356),
 ('teensy._3_1.ADC_REGISTERS.CLP2', 179),
 ('teensy._3_1.ADC_REGISTERS.CLP1', 91),
 ('teensy._3_1.ADC_REGISTERS.CLP0', 45),
 ('teensy._3_1.ADC_REGISTERS.PGA', <ADC_pb2.R_PGA at 0xa2b6830>),
 ('teensy._3_1.ADC_REGISTERS.CLMD', 17),
 ('teensy._3_1.ADC_REGISTERS.CLMS', 43),
 ('teensy._3_1.ADC_REGISTERS.CLM4', 672),
 ('teensy._3_1.ADC_REGISTERS.CLM3', 339),
 ('teensy._3_1.ADC_REGISTERS.CLM2', 170),
 ('teensy._3_1.ADC_REGISTERS.CLM1', 87),
 ('teensy._3_1.ADC_REGISTERS.CLM0', 42)]

In [11]:
adc0_registers.SC3.


Out[11]:
True

In [140]:
proxy.start_timer(20)

In [141]:
%matplotlib inline

In [219]:
frames = []
for i in xrange(100):
    result = proxy.adc_read()
    adc_count = result[:2].view('uint32')[0]
    channel_start_i = [0, 1]
    channel_readings = result[2:]

    #frame = pd.DataFrame([[adc_count[0], adc_count, channel_readings[0]]],
                         #columns=['count', 'adc_count', 'reading'])
    frame = pd.DataFrame(channel_readings, columns=['reading'])
    frame.insert(0, 'adc_count', adc_count)
    frame.insert(0, 'i', i)
    frames.append(frame)
    
readings = pd.concat(frames)

In [227]:
import numpy as np
# print pd.Series(channel_readings[channel_start_i[0]::2]).describe()
# print pd.Series(channel_readings[channel_start_i[1]::2]).describe()

df_i = readings.reset_index(drop=True)
df_i['offset'] = df_i.groupby('i')['adc_count'].transform(lambda v: v & 0x01)

count_scan = np.zeros(df_i.i.unique().shape[0], dtype='uint')
count_scan[1:] = df_i.groupby('i')['adc_count'].count().cumsum()[:-1]
df_i.loc[:, 'count_exc_scan'] = count_scan[df_i['i']]
df_i['group_i'] = np.arange(df_i.shape[0]) - df_i['count_exc_scan'] 
df_i['channel_i'] = 0
df_i.loc[(df_i.group_i & 0x01 == 1) & (df_i.offset == 0), 'channel_i'] = 1
df_i.loc[(df_i.group_i & 0x01 == 0) & (df_i.offset == 1), 'channel_i'] = 1
df_i.drop('count_exc_scan', axis=1, inplace=True)
df_i.loc[(df_i.channel_i == 0) & (df_i.reading < 1000),
         ['group_i', 'channel_i', 'reading']].shape[0]


Out[227]:
256

In [123]:
proxy.dma_available()


Out[123]:
256

In [ ]:
import numpy as np

In [ ]:
def leading_zeros(value, bits=32):
    for i in xrange(bits, 0, -1):
        if (value >> (bits - i)) == 1:
            return i - 1
    return bits


(31 - leading_zeros(256)) << 3

In [ ]:
9 << 3

In [ ]:
import time


N = 32

# proxy.dma_start(1 << int(np.ceil(np.log2(N))))
proxy.dma_start(256)
for i in range(N): proxy.startSingleRead(teensy.A0, teensy.ADC_0)
# time.sleep(0.01)
result = proxy.adc_read()
print result.shape[0]
result

In [ ]:
result = proxy.adc_read()
result.shape[0], result.mean()

In [ ]:
proxy.start_timer(5)

In [ ]:
1 / 100e3 / 1e-6

In [ ]:
proxy.adc_period_us()

In [ ]:
import time


proxy.startContinuous(teensy.A0, teensy.ADC_0)
while proxy.dma_available() < N: time.sleep(0.001)
proxy.stopContinuous(teensy.ADC_0)
proxy.adc_read()

In [ ]:
proxy.enableInterrupts(teensy.ADC_0)

In [ ]:
proxy.adc_timestamp_us()

In [ ]:
# for i in range(128): proxy.startSingleRead(teensy.A0, teensy.ADC_0)
# proxy.startSingleRead(teensy.A0, teensy.ADC_0)

In [ ]:
from datetime import datetime, timedelta

start = datetime.now()
start_us = proxy.microseconds()
proxy.startContinuous(teensy.A0, teensy.ADC_0)
proxy.stopContinuous(teensy.ADC_0)
start + timedelta(microseconds=proxy.adc_timestamp_us() - start_us), proxy.adc_read()

In [ ]:
import time

import pandas as pd

ADC_SPEEDS = pd.Series(['ADC_VERY_LOW_SPEED',
                        'ADC_LOW_SPEED',
                        'ADC_MED_SPEED',
                        # 'ADC_HIGH_SPEED_16BITS',
                        'ADC_HIGH_SPEED',
                        'ADC_VERY_HIGH_SPEED'],
                       index=[teensy.ADC_VERY_LOW_SPEED,
                              teensy.ADC_LOW_SPEED,
                              teensy.ADC_MED_SPEED,
                              # teensy.ADC_HIGH_SPEED_16BITS,
                              teensy.ADC_HIGH_SPEED,
                              teensy.ADC_VERY_HIGH_SPEED])


def benchmark_adc(proxy):
    rows = []

    for conversion_i, conversion_speed in ADC_SPEEDS.iteritems():
        for sampling_i, sampling_speed in ADC_SPEEDS.iteritems():
            for averaging in (0, 4, 8, 16, 32):
                for resolution in (8, 10, 12):
                    if [conversion_i, sampling_i, averaging] == [5, 5, 0]:
                        continue
                    print '.', 
                    try:
                        proxy.setAveraging(averaging, teensy.ADC_0)
                        proxy.setResolution(resolution, teensy.ADC_0)
                        proxy.setConversionSpeed(conversion_i, teensy.ADC_0)
                        proxy.setSamplingSpeed(sampling_i, teensy.ADC_0)

                        proxy.startContinuous(teensy.A0, teensy.ADC_0)
                        time.sleep(0.001)
                        proxy.stopContinuous(teensy.ADC_0)
                        period_us = proxy.adc_period_us()
                    except IOError:
                        print 'Failed for %s' % [conversion_i, sampling_i, averaging,
                                                 resolution]
                        raise
                    row = [conversion_i, sampling_i, averaging,
                           resolution, period_us]
                    rows.append(row)

    df_adc_benchmarks =  pd.DataFrame(rows, columns=['conversion_i',
                                                     'sampling_i',
                                                     'averaging',
                                                     'resolution',
                                                     'period_us'])
    df_adc_benchmarks.loc[df_adc_benchmarks.period_us < 0, 'period_us'] += 1000
#     df_adc_benchmarks.set_index(['conversion_speed', 'sampling_speed',
#                                  'averaging', 'resolution'], inplace=True)
    df_adc_benchmarks['sampling_rate_Hz'] = 1e6 / df_adc_benchmarks['period_us']
    return df_adc_benchmarks

In [ ]:
df_adc_benchmarks = benchmark_adc(proxy)

In [ ]:
%matplotlib inline

In [365]:
teensy.ADC_VERY_HIGH_SPEED


Out[365]:
5

In [ ]:
from si_prefix import si_format


df_i = (df_adc_benchmarks.loc[(df_adc_benchmarks.resolution > 8) &
                              (df_adc_benchmarks.averaging > 0) &
                              (df_adc_benchmarks.sampling_rate_Hz >= 100e3)]
        .sort_values(by=['sampling_rate_Hz', 'resolution', 'conversion_i', 'sampling_i'],
                     ascending=False))
df_i['conversion_speed'] = ADC_SPEEDS[df_i.conversion_i].values
df_i['sampling_speed'] = ADC_SPEEDS[df_i.sampling_i].values
df_i['sampling_rate'] = df_i.sampling_rate_Hz.map(si_format)
df_i[['sampling_rate', 'averaging', 'resolution', 'conversion_speed', 'sampling_speed']]

In [ ]:
df_i[['sampling_rate', 'averaging', 'resolution', 'conversion_speed', 'sampling_speed']]
axis = (df_i.set_index(['averaging', 'resolution', 'conversion_speed', 'sampling_speed'])
        ['sampling_rate_Hz']).plot(rot=90, style='o')
axis.set_yticklabels(['%sHz' % si_format(v) for v in axis.get_yticks()])
# axis.get_figure().savefig('test.pdf', bbox_inches='tight')
pass

In [ ]:
fig.savefig

In [ ]:
import time

import pandas as pd

In [ ]:
proxy.adc_period_us()

In [ ]:
proxy.digital_write(13, 0)

In [ ]:
proxy.startContinuous(teensy.A0, teensy.ADC_0)

In [ ]:
proxy.stopContinuous(teensy.ADC_0)

In [ ]:
proxy.isContinuous(teensy.ADC_0)

In [ ]:
if proxy.dma_available() > 0:
    print proxy.dma_read()
proxy.adc_buffer(), proxy.dma_available()

In [ ]:
proxy.startSingleRead(teensy.A0, teensy.ADC_0)

In [ ]:
proxy.dma_available(), proxy.dma_empty(), proxy.dma_full()

In [ ]:
proxy.dma_read()

In [ ]:
proxy.start_timer(10)

In [ ]:
%matplotlib inline
import pandas as pd

In [ ]:
from datetime import datetime

In [ ]:
proxy.setAveraging(0, -1)

In [ ]:
data = pd.DataFrame([(proxy.analogRead(0, -1), datetime.now()) for i in xrange(200)],
                    columns=['reading', 'timestamp'])
data.set_index('timestamp').plot()

In [ ]:
proxy.adc_buffer

In [ ]:
40 * proxy.benchmark_flops(10e3) / 10e3

In [ ]:
40 * proxy.benchmark_iops(10e3) / 10e3

In [ ]:
import sys
sys.path.insert(0, r'C:\Users\Christian\Documents\GitHub\ring-buffer-testbench')

In [ ]:
from ring_buffer_testbench.cRingBuffer import cRingBuffer

In [ ]:
ring_buffer = cRingBuffer()

In [ ]:
ring_buffer.elems(), ring_buffer.b_start, ring_buffer.b_end